#ifndef MLOADER_IMAGE
#define MLOADER_IMAGE

#include "Common.h"
#include <iostream>
#include <fstream>

namespace MLoader
{
	class Image
	{
	public:
		typedef enum Type
		{
			TGA,
			PNG
		} Type;

		Image():_w(0), _h(0), _pps(0) { };
		Image(const int& w, const int&h, const int&pps):_w(w),_h(h),_pps(pps)
		{
			_data.resize(w * h * pps, 0);
		}

		virtual bool ReadFile(const std::string filename) = 0;
		virtual bool WriteFile(const std::string filename, const bool vflip = true, const bool rle = true) const = 0;

		std::uint32_t* Get(const int& x, const int& y)
		{
			if (_data.empty()) return nullptr;

			return (std::uint32_t*)(_data.data() + (x + y * _w) * _pps);
		}

		int Width() { return _w; }
		int Height() { return _h; }
		int PixelSize() { return _pps; }
		std::uint8_t* Buffer() { return _data.data(); }

	protected:
		int _w;
		int _h;
		int _pps; // per pixel size of bytes
		std::vector<std::uint8_t> _data;
	};

	class ImageBMP : public Image
	{
	public:

		virtual bool ReadFile(const std::string filename);
		virtual bool WriteFile(const std::string filename, const bool vflip = true, const bool rle = true) const;
	};

	class ImageTGA : public Image
	{
	public:
		typedef enum Format {
			GRAY = 1,
			RGB  = 3,
			RGBA = 4
		} Format;

		virtual bool ReadFile(const std::string filename);
		virtual bool WriteFile(const std::string filename, const bool vflip = true, const bool rle = true) const;

	private:
		struct Header {
			std::uint8_t  id_length{};
			std::uint8_t  color_map_type{};
			std::uint8_t  data_type_code{};
			std::uint16_t color_map_origin{};
			std::uint16_t color_map_length{};
			std::uint8_t  color_map_depth{};
			std::uint16_t x_origin{};
			std::uint16_t y_origin{};
			std::uint16_t width{};
			std::uint16_t height{};
			std::uint8_t  bits_per_pixel{};
			std::uint8_t  image_descriptor{};
		};

		void flip_horizontally();
		void flip_vertically();
		bool   load_rle_data(std::ifstream &in);
		bool unload_rle_data(std::ofstream &out) const;
	};

	class ImagePNG : public Image
	{
	public:
		//typedef enum Format {
		//	GRAY = 1,
		//	RGB = 3,
		//	RGBA = 4
		//} Format;

		virtual bool ReadFile(const std::string filename);
		virtual bool WriteFile(const std::string filename, const bool vflip = true, const bool rle = true) const;
	};
}

#endif // MLOADER_IMAGE